重温——apply和call方法

以前,自己都是通过把笔记、容易忘和经常需要用的知识都记录在自己本地的文件里面。既然有了博客,这两天刚好整理一下原来的笔记,把现在还认为不错的分享到博客上。来第一篇先分享一下常见的apply和call方法
在说apply和call之前,首先你必须要知道javascript中的上下文环境:(PS:不懂的童鞋可以自行百度,下回在原型与闭包的分享中也会做比较详细的说明)。这里先说两点:
一、javascript中的this关键字指向的是包含当前方法的那个对象;
二、而在面向对象的javascript编程中,this指向的就是由某个”类”创建的一个对象实例。

apply和call方法的主要两个功能

一、在需要改变调用函数this的时候,或者调用本身对象没有的方法的时候:当调用其他对象而非代表当前上下文的对象的方法时,该方法中所有对this的引用都指向此方法所在的对象,而非当前代码的执行的上下文——就是说在调用这个方法时,你切换到了另外一个上下文中。在调用其他对象的方法时,我们利用apply和call方法保持this原来的值。
二、javascript继承。

apply和call的区别

call和apply的区别在于,使用apply时,所有参数都应放在一个单独的数组参数中,而在使用call的时候,参数应该一次列出,并用逗号隔开。
例:使用apply和call方法调用别的对象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//定义一个简单的"类"
function Accommodation(){
this.isAlarmed = false;
}
//创建一个对象,其方法可以被代码中的其他对象所使用
var AlarmSysten = {
arm:function(message){
this.isAlarmed = true;
alert(message);
},
disarm:function(message){
this.isAlarmed = false;
alert(message);
}
};
var myHouse = new Accommodation();
//通过call,将对象实例上下文传入arm函数
AlarmSysten.arm.call(myHouse,"Alarm activated");

//arm函数中this的值指向通过call传入的对象实例,所以myHouse对象的isAlarmed属性被改变了
alert(myHouse.isAlarmed);//true

//通过apply也能达到同样的效果,只不过是参数是通过数组来进行传递的
AlarmSysten.disarm.apply(myHouse,["Alarm activated"]);
alert(myHouse.isAlarmed);//false

例:改变上下文环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//如果单纯只是在一个函数中调用另一个函数是没什么多大区别,apply / call 的最大作用就是改变上下文
var name = "张三";
//在全局里定义函数func1
function getName(){
return this.name;
}

//在对象里定义函数func2
var obj = {
name:"李四",
showName:function(){
console.log(getName()) //这里直接调用,"张三"
return getName.apply(this); //在showName里调用getName,并将this从window改变为obj;也可以说是在obj对象中(obj的上下文环境中)调用window环境中的getName函数,利用apply方法保持了this原来的值。
}
};,

console.log(obj.showName()); //obj调用,"李四"

例:继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
function base() {
this.member = " dnnsun_Member";
this.method = function() {
window.alert(this.member);
}
}
function extend() {
base.call(this);
window.alert(member); //" dnnsun_Member"
window.alert(this.method); //method方法
}
extend();
//上面的例子可以看出,通过call之后,extend可以继承到base的方法和属性。
//顺便提一下,在javascript框架prototype里就使用apply来创建一个定义类的模式,
//其实现代码如下:
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
//解析:从代码看,该对象仅包含一个方法:Create,其返回一个函数,即类。但这也同时是类的
//构造函数,其中调用initialize,而这个方法是在类创建时定义的初始化函数。通过如此途径,
//就可以实现prototype中的类创建模式
//示例:
var vehicle = Class.create();
vehicle.prototype.initialize= function(type){
this.type=type;
}
vehicle.prototype.showSelf= function(){
alert("this vehicle is "+ this.type);
}

var moto=new vehicle("Moto");
moto.showSelf(); //"this vehicle is Moto"